package com.kinyx.framework.bean.define;

import java.util.Date;

import com.kinyx.framework.annotation.assist.CanNotNull;
import com.kinyx.framework.annotation.assist.CanNull;
import com.kinyx.framework.annotation.assist.ReturnNotNull;
import com.kinyx.framework.bean.StringFormatter;
import com.kinyx.framework.business.KRandomUtils;
import com.kinyx.framework.enums.impl.ErrorCodeX;
import com.kinyx.framework.enums.impl.RandomRange;
import com.kinyx.framework.exception.KException;
import com.kinyx.framework.exception.KRuntimeException;
import com.kinyx.framework.log.Log;
import com.kinyx.framework.utils.KDateTimeUtils;

/**
 * 方法参数
 */
public abstract class MethodParam {

	/** 日志对象 */
	private Log logger;

	/**
	 * trace级别是否可用
	 * @return true: 可用; false: 不可用;
	 */
	public boolean isTraceEnabled() { return this.logger.isTraceEnabled(); }
	/**
	 * debug级别是否可用
	 * @return true: 可用; false: 不可用;
	 */
	public boolean isDebugEnabled() { return this.logger.isDebugEnabled(); }
	/**
	 * info级别是否可用
	 * @return true: 可用; false: 不可用;
	 */
	public boolean isInfoEnabled() { return this.logger.isInfoEnabled(); }
	/**
	 * warn级别是否可用
	 * @return true: 可用; false: 不可用;
	 */
	public boolean isWarnEnabled() { return this.logger.isWarnEnabled(); }
	/**
	 * error级别是否可用
	 * @return true: 可用; false: 不可用;
	 */
	public boolean isErrorEnabled() { return this.logger.isErrorEnabled(); }
	/**
	 * fatal级别是否可用
	 * @return true: 可用; false: 不可用;
	 */
	public boolean isFatalEnabled() { return this.logger.isFatalEnabled(); }
	/**
	 * 输出日志
	 * @param message 日志信息
	 */
	public void trace(final Object message) { this.logger.trace(this.contents(null, message == null ? null : message.toString())); }
	/**
	 * 输出日志
	 * @param message 日志信息
	 */
	public void debug(final Object message) { this.logger.debug(this.contents(null, message == null ? null : message.toString())); }
	/**
	 * 输出日志
	 * @param message 日志信息
	 */
	public void info(final Object message) { this.logger.info(this.contents(null, message == null ? null : message.toString())); }
	/**
	 * 输出日志
	 * @param message 日志信息
	 */
	public void warn(final Object message) { this.logger.warn(this.contents(null, message == null ? null : message.toString())); }
	/**
	 * 输出日志
	 * @param message 日志信息
	 */
	public void error(final Object message) { this.logger.error(this.contents(null, message == null ? null : message.toString())); }
	/**
	 * 输出日志
	 * @param message 日志信息
	 */
	public void fatal(final Object message) { this.logger.fatal(this.contents(null, message == null ? null : message.toString())); }
	/**
	 * 输出日志
	 * @param message 日志信息
	 * @param t 异常对象
	 */
	public void trace(final Object message, final Throwable t) { this.logger.trace(this.contents(t, message == null ? null : message.toString())); }
	/**
	 * 输出日志
	 * @param message 日志信息
	 * @param t 异常对象
	 */
	public void debug(final Object message, final Throwable t) { this.logger.debug(this.contents(t, message == null ? null : message.toString())); }
	/**
	 * 输出日志
	 * @param message 日志信息
	 * @param t 异常对象
	 */
	public void info(final Object message, final Throwable t) { this.logger.info(this.contents(t, message == null ? null : message.toString())); }
	/**
	 * 输出日志
	 * @param message 日志信息
	 * @param t 异常对象
	 */
	public void warn(final Object message, final Throwable t) { this.logger.warn(this.contents(t, message == null ? null : message.toString())); }
	/**
	 * 输出日志
	 * @param message 日志信息
	 * @param t 异常对象
	 */
	public void error(final Object message, final Throwable t) { this.logger.error(this.contents(t, message == null ? null : message.toString())); }
	/**
	 * 输出日志
	 * @param message 日志信息
	 * @param t 异常对象
	 */
	public void fatal(final Object message, final Throwable t) { this.logger.fatal(this.contents(t, message == null ? null : message.toString())); }

	/**
	 * 构造方法
	 * @param logger 日志对象
	 */
	protected MethodParam(@CanNull final Log logger) { super(); this.logger = logger; }
	/**
	 * 设置日志对象
	 * @param logger 日志对象
	 */
	public void setIfLoggerIsNull(@CanNotNull final Log logger) {
		if (this.logger == null) { this.logger = logger; }
	}
	/** 唯一标识 */
	protected String id;
	/** 开始时间 */
	protected Date startTime;
	/** 结束时间 */
	protected Date endTime;
	/** 持续时长 */
	protected long elapsedTime;

	/** 主参数对象 */
	protected MethodParam main;

	/** @return true：是主参数；false：非主参数： */
	public boolean isMain() { return this.main == null; }

	/**
	 * 初始化参数
	 */
	protected void init() {
		if (this.id == null) {
			this.id = KRandomUtils.randomString(false, 16, RandomRange.NUMBER_AND_LETTER_FULL);
			this.startTime = new Date();
		}
	}

	/**
	 * 初始化子参数
	 * @param subParam 子参数对象
	 */
	protected void initSubParam(@CanNotNull final MethodParam subParam) {
		subParam.logger = this.logger;
		subParam.id = this.id + "-" + KRandomUtils.randomString(false, 15, RandomRange.NUMBER_AND_LETTER_FULL);
		subParam.startTime = new Date();

		subParam.main = this;
	}

	private boolean logBeforeCalled;
	/**
	 * 记录开始日志
	 */
	public void logBeforeExecution() {
		if (this.logBeforeCalled) { throw new KRuntimeException(ErrorCodeX.RepeatCall); }
		this.logBeforeCalled = true;
		this.logBeforeExecutionImpl();
	}

	/**
	 * 记录开始日志
	 */
	protected void logBeforeExecutionImpl() {
		if (this.isTraceEnabled()) { this.trace(null); }
	}

	private boolean logAfterCalled;
	/**
	 * 记录结束日志
	 * @param e 异常
	 */
	public void logAfterExecution(@CanNull final Throwable e) {
		if (this.logAfterCalled) { throw new KRuntimeException(ErrorCodeX.RepeatCall); }
		this.logAfterCalled = true;
		if (e != null) {// 执行异常
			this.fatal(null, e);
			if (this.main != null) { this.main.logAfterExecution(e); }
			return;
		}
		this.endTime = new Date();
		this.elapsedTime = this.endTime.getTime() - this.startTime.getTime();
		this.logAfterExecutionImpl();
	}

	/**
	 * 记录结束日志
	 */
	protected void logAfterExecutionImpl() {
		if (this.isDebugEnabled()) { this.debug(null); }
	}

	/**
	 * 创建日志内容
	 * @param e 异常
	 * @param content 日志内容
	 * @return 日志内容
	 */
	@ReturnNotNull
	private String contents(@CanNull final Throwable e, @CanNull final String content) {
		final StringFormatter sfb = StringFormatter.of();
		this.contentsImplBefore(sfb);

		final StringFormatter sfa = StringFormatter.of();
		if (e != null) {
			sfa.x("exception occurred [%s]", () -> { return e != null; }, () -> {
				if (e instanceof KRuntimeException) {
					final Throwable cause = ((KRuntimeException) e).getCause();
					if (cause == null) { return e.getMessage(); }
					return e.getMessage() + " -> " + cause.getMessage();
				}
				if (e instanceof KException) {
					final Throwable cause = ((KException) e).getCause();
					if (cause == null) { return e.getMessage(); }
					return e.getMessage() + " -> " + cause.getMessage();
				}
				return e.getMessage();
			})//
			;
		} else {
			if (content != null) {
				sfa.s(content);
			} else {
				sfa//
						.x("starting at %s.", () -> { return this.endTime == null; }, KDateTimeUtils.toString(this.startTime, "yyyyMMddHHmmssSSS"))//
						.x("finished at %s, execution takes %sms.", () -> { return this.endTime != null; }, () -> { return KDateTimeUtils.toString(this.endTime, "yyyyMMddHHmmssSSS"); }, () -> { return this.elapsedTime; })//
				;
			}
		}
		this.contentsImplAfter(sfa);
		return String.format("[%s]%s %s", this.id, sfb.format(), sfa.format());
	}

	/**
	 * 创建日志内容
	 * @param sf 字符串格式化对象
	 */
	protected void contentsImplBefore(final StringFormatter sf) {}
	/**
	 * 创建日志内容
	 * @param sf 字符串格式化对象
	 */
	protected abstract void contentsImplAfter(@CanNotNull StringFormatter sf);

}
